package at.codebase.web.servlets;

import static at.codebase.web.util.i18n.I18NFactory.i18n;

import java.util.ArrayList;
import java.util.List;

import at.codebase.core.LinkCreator;
import at.codebase.core.PageLinkFactory;
import at.codebase.core.ServletList;
import at.codebase.core.search.ItemSearch;
import at.codebase.core.search.ItemSearchResult;
import at.codebase.core.search.ItemSearchResultInfo;
import at.codebase.core.search.SortOption;
import at.codebase.core.search.SortOption.SortOptionDetail;
import at.codebase.core.search.SortOption.SortOptionType;
import at.codebase.core.search.SortOptionsFormFactory;
import at.codebase.db.dao.EItemDao;
import at.codebase.db.entities.EImage;
import at.codebase.db.entities.EItem;
import at.codebase.security.SecureStringBuilder;
import at.codebase.security.SecurityUtils;
import at.codebase.web.templates.MainTemplate;
import at.codebase.web.util.LocalRequest.RequestInformation;
import at.codebase.web.util.URLParameters;
import at.codebase.web.util.URLParameters.ParameterDoesNotExistException;
import at.codebase.web.util.URLParameters.ParameterParsingException;
import at.codebase.web.util.i10n.L10N;
import at.codebase.web.util.servlet.SecureServlet;
import at.codebase.web.util.template.Template;
import at.codebase.web.util.template.TemplateEngine;

import com.google.appengine.api.search.GeoPoint;
import com.googlecode.objectify.Key;

/**
 * Search page.
 * 
 * @author Daniel Marth <danielmarth@gmx.at>
 */
public class Search extends SecureServlet {

	private final static int NewestItemsCount = 8;
	private final static int ItemsPerPage = 10;
	private final static int MaxFilterLevels = 5;

	@Override
	protected void initSecurityLevels(ArrayList<UserLevel> secLevels) {
		secLevels.add(UserLevel.ANONYMOUS);
		secLevels.add(UserLevel.REGISTERED);
		secLevels.add(UserLevel.ADMIN);
	}

	@Override
	protected void processRequestSecurityLevel(RequestInformation requestInfo,
			final UserLevel level, final RequestType requestType) {
		if (requestInfo.getParameters().isExisting("query")) {
			showSearchResults(requestInfo);
		} else {
			showDefaultSearch(requestInfo);
		}
	}

	private void showDefaultSearch(RequestInformation requestInfo) {
		MainTemplate mainTemplate = new MainTemplate(requestInfo, writer());
		mainTemplate.setTitle(i18n(requestInfo.getLocale()).string(
				"item_newest"));

		Template newItemTemplate = TemplateEngine
				.getTemplate("search/default_search.html");
		newItemTemplate.setText("item_newest", i18n(requestInfo.getLocale())
				.string("item_newest"));
		List<EItem> newestItems = EItemDao.getNewestItems(NewestItemsCount);
		ArrayList<Template> rows = new ArrayList<Template>();
		for (EItem item : newestItems) {
			if (item.getTimeExpiration() > System.currentTimeMillis() && item.isActive()) {
				Template unitTemplate = TemplateEngine
						.getTemplate("search/item_unit.html");
				ArrayList<Key<EImage>> images = item.getImageKeys();
				if (images.size() > 0) {
					unitTemplate.setText("imageUrl", "/service/image?id="
							+ images.get(0).getId() + "&w=110&h=110");
				} else {
					unitTemplate.setText("imageUrl",
							"/images/no_image_available.png");
				}

				unitTemplate.setText("itemId", item.getId().toString());
				unitTemplate.setHTML("title",
						LinkCreator.itemLink(item.getId(), item.getTitle()));
				String description = item.getDescription();
				if (description.length() > 260)
					description = description.substring(0, 260) + "... ";
				unitTemplate.setText("description", description);
				unitTemplate.setHTML(
						"time",
						i18n(requestInfo.getLocale()).string(
								"search_itemList_createTime",
								L10N.formatDate(requestInfo.getLocale(),
										item.getTimeCreate())/*
															 * ,
															 * L10N.formatTime(
															 * requestInfo
															 * .getLocale(),
															 * item
															 * .getTimeCreate())
															 */));
				unitTemplate.setHTML(
						"price",
						i18n(requestInfo.getLocale()).string(
								"search_itemList_price",
								L10N.formatMoney(requestInfo.getLocale(),
										item.getPrice())));
				rows.add(unitTemplate);
			}
		}
		newItemTemplate.setTemplates("newestItems", rows);
		mainTemplate.setTemplate("body", newItemTemplate);
		mainTemplate.setText("search_results", i18n(requestInfo.getLocale())
				.string("search_results"));
		mainTemplate.render(requestInfo.getLocale());
	}

	private void showSearchResults(RequestInformation requestInfo) {
		URLParameters params = requestInfo.getParameters();

		try {
			String query = SecurityUtils.sanatizeSearchQuery(params
					.getString("query"));
			int currentPage = 1;
			int lastPage = 1;
			int page = 1;
			ItemSearchResultInfo resultInfo;
			boolean usesLocation = false;

			ArrayList<SortOption> sortOptions = new ArrayList<SortOption>();

			SecureStringBuilder urlBuilder = new SecureStringBuilder();

			for (int i = 1; i <= MaxFilterLevels; i++) {
				if (params.isExisting("sort" + i)) {
					String sortValue = params.getString("sort" + i);
					if (sortValue.contains("_")) {
						// Type
						String sortTypeString = sortValue.split("_")[0];
						SortOptionType sortType = SortOption.sortTypes
								.get(sortTypeString);
						if (sortType == SortOptionType.LOCATION) {
							usesLocation = true;
						}

						// Direction
						String sortDetailString = sortValue.split("_")[1];
						SortOptionDetail sortDetail = SortOption.sortDetails
								.get(sortDetailString);

						if (sortDetail != null && sortType != null) {

							urlBuilder.appendInsecure("&sort");
							urlBuilder.appendInsecure(String.valueOf(i));
							urlBuilder.appendInsecure("=");
							urlBuilder.appendInsecure(sortTypeString);
							urlBuilder.appendInsecure("_");
							urlBuilder.appendInsecure(sortDetailString);

							sortOptions
									.add(new SortOption(sortType, sortDetail));
						}
					}
				}
			}

			double latitude = 0.0, longitude = 0.0;
			int distance = 0;
			if (usesLocation) {
				try {
					latitude = params.getDouble("latitude");
					longitude = params.getDouble("longitude");
					distance = params.getInteger("distance");
				} catch (ParameterDoesNotExistException ex) {
					usesLocation = false;
				} catch (ParameterParsingException ex) {
					usesLocation = false;
				}
			}

			long startTime = System.currentTimeMillis();
			if (!requestInfo.getParameters().isExisting("page")) {
				if (sortOptions.size() > 0) {
					if (usesLocation) {
						resultInfo = ItemSearch.searchClosest(query,
								ItemsPerPage, 0, sortOptions, new GeoPoint(
										latitude, longitude), distance);
					} else {
						resultInfo = ItemSearch.searchSorted(query,
								ItemsPerPage, 0, sortOptions);
					}
				} else {
					resultInfo = ItemSearch.search(query, ItemsPerPage, 0);
				}
			} else {
				page = requestInfo.getParameters().getInteger("page");
				if (page < 1) {
					page = 1;
				}
				if (sortOptions.size() > 0) {
					if (usesLocation) {
						resultInfo = ItemSearch.searchClosest(query,
								ItemsPerPage, (page - 1) * ItemsPerPage,
								sortOptions, new GeoPoint(latitude, longitude),
								distance);
					} else {
						resultInfo = ItemSearch.searchSorted(query,
								ItemsPerPage, (page - 1) * ItemsPerPage,
								sortOptions);
					}
				} else {
					resultInfo = ItemSearch.search(query, ItemsPerPage,
							(page - 1) * ItemsPerPage);
				}
				currentPage = page;
			}
			if (resultInfo.getCount() > ItemsPerPage) {
				lastPage = (int) Math.ceil((double) resultInfo.getCount()
						/ (double) ItemsPerPage);
				if (lastPage == 0) {
					lastPage = 1;
				}
			}
			if (page > lastPage) {
				page = lastPage;
			}
			long endTime = System.currentTimeMillis();
			MainTemplate mainTemplate = new MainTemplate(requestInfo, writer());
			mainTemplate.setTitle(i18n(requestInfo.getLocale()).string(
					"search_title")
					+ " - " + SecurityUtils.sanatize(query));
			mainTemplate.addJSScript("script_search.js");
			mainTemplate.setSearchInput(query);

			Template searchResultTemplate = TemplateEngine
					.getTemplate("search/search_results.html");
			searchResultTemplate.setText("search_results",
					i18n(requestInfo.getLocale()).string("search_results"));
			ArrayList<Template> rows = new ArrayList<Template>();
			for (ItemSearchResult searchItem : resultInfo.getResults()) {
				EItem item = searchItem.getItem();
				Template unitTemplate = TemplateEngine
						.getTemplate("search/item_unit.html");
				ArrayList<Key<EImage>> images = item.getImageKeys();
				if (images.size() > 0) {
					unitTemplate.setText("imageUrl", "/service/image?id="
							+ images.get(0).getId() + "&w=110&h=110");
				} else {
					unitTemplate.setText("imageUrl",
							"/images/no_image_available.png");
				}

				unitTemplate.setText("itemId", item.getId().toString());
				if (!searchItem.getTitleSnippet().isEmpty()) {
					unitTemplate.setHTML("title", LinkCreator.itemLinkInsecure(
							item.getId(), searchItem.getTitleSnippet()));
				} else {
					unitTemplate
							.setHTML(
									"title",
									LinkCreator.itemLink(item.getId(),
											item.getTitle()));
				}
				if (!searchItem.getDescriptionSnippet().isEmpty()) {
					unitTemplate.setHTML("description",
							searchItem.getDescriptionSnippet());
				} else {
					String description = item.getDescription();
					if (description.length() > 260)
						description = description.substring(0, 260) + "... ";
					unitTemplate.setText("description", description);
				}

				unitTemplate.setHTML(
						"time",
						i18n(requestInfo.getLocale()).string(
								"search_itemList_createTime",
								L10N.formatDate(requestInfo.getLocale(),
										item.getTimeCreate())/*
															 * ,
															 * L10N.formatTime(
															 * requestInfo
															 * .getLocale(),
															 * item
															 * .getTimeCreate())
															 */));
				unitTemplate.setHTML(
						"price",
						i18n(requestInfo.getLocale()).string(
								"search_itemList_price",
								L10N.formatMoney(requestInfo.getLocale(),
										item.getPrice())));
				rows.add(unitTemplate);
			}

			searchResultTemplate.setTemplates("searchResults", rows);

			searchResultTemplate.setHTML(
					"resultInfo",
					i18n(requestInfo.getLocale()).string("search_result_info",
							String.valueOf(resultInfo.getCount()),
							String.valueOf(endTime - startTime)));
			searchResultTemplate.setText("searchQuery", query);

			String baseUrl = new SecureStringBuilder()
					.appendInsecure(
							ServletList.SearchQueryWithPage.replace("{query}",
									query)).append(urlBuilder).toString();
			searchResultTemplate
					.setHTML("pageLinks", PageLinkFactory.createLinks(baseUrl,
							currentPage, lastPage));

			searchResultTemplate.setTemplate("sortOptions",
					SortOptionsFormFactory.createSortOptions(requestInfo,
							query, sortOptions));

			mainTemplate.setTemplate("body", searchResultTemplate);
			mainTemplate.render(requestInfo.getLocale());

		} catch (ParameterDoesNotExistException e) {
			// TODO Auto-generated catch block
		} catch (ParameterParsingException e) {
			// TODO Auto-generated catch block
		}
	}

}
